//
//  PacketTunnelProvider.swift
//  Mars-tunnel
//
//  Created by PowerfullClean on 2023/10/17.
//

import NetworkExtension
import PacketProcessor_iOS
import os.log

class PacketTunnelProvider: NEPacketTunnelProvider {
    
    private var mapy_cuVPs: MAPYShadowSocksManager?
    private var mapy_cuCPCOmHandler: ((Error?) -> Void)?
    
    override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
        MAPYPrintput("options: \(options?.description ?? "")")
        guard let mapy_vpfo = options?["options"] as? [String : Any] else {
            completionHandler(NEVPNError(.configurationDisabled))
            return
        }

        self.mapy_cuCPCOmHandler = completionHandler
        self.mapy_cuVPs = MAPYShadowSocksManager(mapy_vpfo)
        
        mapy_cuVPs?.start(withConnectivityChecks: false) { [weak self] error in
            if error == .noError {
                self?.mapy_setNetSeings()
            } else {
                self?.mapy_cuCPCOmHandler?(NEVPNError(.connectionFailed))
            }
        }
    }
    
    private func mapy_setNetSeings() {
        let ipList = [String]()
        
        var ipV4ExcludedRoutes = [NEIPv4Route]()
        var ipV6ExcludedRoutes = [NEIPv6Route]()
        
        ipList.forEach { ip in
            if ip.contains(":") {
                ipV6ExcludedRoutes.append(NEIPv6Route(destinationAddress: ip, networkPrefixLength: 128))
            } else {
                ipV4ExcludedRoutes.append(NEIPv4Route(destinationAddress: ip, subnetMask: "255.255.255.255"))
            }
        }
        
        let mapy_ipV4Sting = NEIPv4Settings(addresses: ["192.168.20.2"], subnetMasks: ["255.255.255.0"])
        mapy_ipV4Sting.includedRoutes = [.default()]
        mapy_ipV4Sting.excludedRoutes = ipV4ExcludedRoutes
        
        let mapy_ipV6Sting = NEIPv6Settings(addresses: ["fd66:f83a:c650::1"], networkPrefixLengths: [120])
        mapy_ipV6Sting.includedRoutes = [.default()]
        mapy_ipV6Sting.excludedRoutes = ipV6ExcludedRoutes
        
        let mapy_dnsSegs = NEDNSSettings(servers: ["8.8.8.8", "8.8.4.4", "1.1.1.1", "1.0.0.1"])
        
        let mapy_routsetting = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "192.168.20.1")
        mapy_routsetting.ipv4Settings = mapy_ipV4Sting
        mapy_routsetting.ipv6Settings = mapy_ipV6Sting
        mapy_routsetting.dnsSettings = mapy_dnsSegs
        
        setTunnelNetworkSettings(mapy_routsetting) { error in
            if let error = error {
                self.mapy_cuCPCOmHandler?(error)
                return
            }
            self.mapy_setSSTunnel()
        }
    }
    
    private func mapy_setSSTunnel() {
        if let error = TunnelInterface.setup(with: self.packetFlow) {
            self.mapy_cuCPCOmHandler?(error)
            return
        }
        
        let port: Int32 = self.mapy_cuVPs!.localSSPort
        TunnelInterface.setIsUdpForwardingEnabled(true)
        TunnelInterface.startTun2Socks(port)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            TunnelInterface.processPackets()
        }
        
        self.mapy_cuCPCOmHandler?(nil)
    }
    
    override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
        TunnelInterface.stop()
        mapy_cuVPs?.stop({ _ in
            
        })
        completionHandler()
    }
    
    override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
        if let msg = String(data: messageData, encoding: String.Encoding.utf8) {
            if msg == "CANCEL_VPN" {
                mapy_cuVPs?.stop({ _ in
                })
                return
            }
        }
        if let handler = completionHandler {
            handler(messageData)
        }
    }
    
    override func sleep(completionHandler: @escaping () -> Void) {
        completionHandler()
    }
    
    
    private func MAPYPrintput(_ content: String) {
#if DEBUG
        os_log(" %{public}s", content)
#endif
    }
    
}

